<template>
  <div class="">
    <template v-if="this.useSuggestions">
      <a-result
        title="当前工作空间还没有项目并且也没有任何节点"
        sub-title="需要您先新增资产机器再分配机器节点（逻辑节点）到当前工作空间"
      >
      </a-result>
    </template>
    <a-table
      v-else
      :data-source="projList"
      :columns="columns"
      size="middle"
      bordered
      :pagination="pagination"
      @change="changePage"
      :row-selection="rowSelection"
      rowKey="id"
      :scroll="{
        x: 'max-content'
      }"
    >
      <template v-slot:title>
        <a-space wrap class="search-box">
          <a-select
            v-if="!nodeId"
            v-model:value="listQuery.nodeId"
            allowClear
            placeholder="请选择节点"
            class="search-input-item"
          >
            <a-select-option v-for="(nodeName, key) in nodeMap" :key="key">{{ nodeName }}</a-select-option>
          </a-select>
          <a-select
            v-model:value="listQuery.group"
            allowClear
            placeholder="请选择分组"
            class="search-input-item"
            @change="getNodeProjectData"
          >
            <a-select-option v-for="group in groupList" :key="group">{{ group }}</a-select-option>
          </a-select>
          <a-input
            v-model:value="listQuery['%name%']"
            @pressEnter="getNodeProjectData"
            placeholder="搜索项目名"
            class="search-input-item"
          />
          <a-input
            v-model:value="listQuery['%projectId%']"
            @pressEnter="getNodeProjectData"
            placeholder="搜索项目ID"
            class="search-input-item"
          />

          <a-select v-model:value="listQuery.runMode" allowClear placeholder="项目类型" class="search-input-item">
            <a-select-option v-for="item in runModeList" :key="item">{{ item }}</a-select-option>
          </a-select>
          <a-tooltip title="按住 Ctr 或者 Alt/Option 键点击按钮快速回到第一页">
            <a-button :loading="loading" type="primary" @click="getNodeProjectData">搜索</a-button>
          </a-tooltip>

          <a-dropdown v-if="this.selectedRowKeys && this.selectedRowKeys.length">
            <a-button type="primary"> 操作 <DownOutlined /> </a-button>
            <template v-slot:overlay>
              <a-menu>
                <a-menu-item>
                  <a-button type="primary" @click="batchStart">批量启动</a-button>
                </a-menu-item>
                <a-menu-item>
                  <a-button type="primary" @click="batchRestart">批量重启</a-button>
                </a-menu-item>
                <a-menu-item>
                  <a-button type="primary" danger @click="batchStop">批量关闭</a-button>
                </a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>
          <a-button v-else type="primary" :disabled="true"> 操作 <DownOutlined /> </a-button>

          <a-button type="primary" @click="openAdd">新增</a-button>
          <template v-if="!nodeId">
            <a-dropdown v-if="nodeMap && Object.keys(nodeMap).length">
              <a-button type="primary" danger> 同步 <DownOutlined /></a-button>
              <template v-slot:overlay>
                <a-menu>
                  <a-menu-item v-for="(nodeName, key) in nodeMap" :key="key" @click="reSyncProject(key)">
                    <a href="javascript:;">{{ nodeName }} <SyncOutlined /></a>
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </template>
          <a-button v-else type="primary" danger @click="reSyncProject(nodeId)"> <SyncOutlined />同步 </a-button>

          <a-button v-if="nodeId" type="primary" @click="handlerExportData()"><DownloadOutlined />导出</a-button>
          <a-dropdown v-if="nodeId">
            <template v-slot:overlay>
              <a-menu>
                <a-menu-item key="1">
                  <a-button type="primary" @click="handlerImportTemplate()">下载导入模板</a-button>
                </a-menu-item>
              </a-menu>
            </template>

            <a-upload
              name="file"
              accept=".csv"
              action=""
              :showUploadList="false"
              :multiple="false"
              :before-upload="importBeforeUpload"
            >
              <a-button type="primary"><UploadOutlined /> 导入 <DownOutlined /> </a-button>
            </a-upload>
          </a-dropdown>

          <a-tooltip>
            <template v-slot:title>
              <div>
                <ul>
                  <li>状态数据是异步获取有一定时间延迟</li>
                  <li>在单页列表里面 file 类型项目将自动排序到最后</li>
                </ul>
              </div>
            </template>
            <QuestionCircleOutlined />
          </a-tooltip>
          <a-statistic-countdown format=" s 秒" title="刷新倒计时" :value="countdownTime" @finish="silenceLoadData" />
        </a-space>
      </template>
      <template #bodyCell="{ column, text, record, index }">
        <template v-if="column.dataIndex === 'name'">
          <a-tooltip placement="topLeft" :title="text">
            <a-button type="link" style="padding: 0" size="small" @click="openEdit(record)">
              <ApartmentOutlined v-if="record.outGivingProject" />
              <span>{{ text }}</span>
            </a-button>
          </a-tooltip>
        </template>
        <template v-else-if="column.dataIndex === 'nodeId'">
          <a-tooltip placement="topLeft" :title="text">
            <a-button type="link" style="padding: 0" size="small" @click="toNode(text)">
              <span>{{ nodeMap[text] }}</span>
              <FullscreenOutlined />
            </a-button>
          </a-tooltip>
        </template>
        <template v-else-if="column.dataIndex === 'path'">
          <a-tooltip placement="topLeft" :title="(record.whitelistDirectory || '') + (record.lib || '')">
            <span>{{ (record.whitelistDirectory || '') + (record.lib || '') }}</span>
          </a-tooltip>
        </template>

        <template v-else-if="column.tooltip">
          <a-tooltip placement="topLeft" :title="text">
            <span>{{ text || '' }}</span>
          </a-tooltip>
        </template>

        <template v-else-if="column.dataIndex === 'status'">
          <template
            v-if="
              projectStatusMap[record.nodeId] &&
              projectStatusMap[record.nodeId][record.projectId] &&
              projectStatusMap[record.nodeId][record.projectId].error
            "
          >
            <a-tooltip
              :title="
                projectStatusMap[record.nodeId] &&
                projectStatusMap[record.nodeId][record.projectId] &&
                projectStatusMap[record.nodeId][record.projectId].error
              "
            >
              <WarningOutlined />
            </a-tooltip>
          </template>
          <template v-else>
            <a-tooltip
              v-if="noFileModes.includes(record.runMode)"
              :title="`状态操作请到控制台中控制   ${
                (projectStatusMap[record.nodeId] &&
                  projectStatusMap[record.nodeId][record.projectId] &&
                  projectStatusMap[record.nodeId][record.projectId].statusMsg) ||
                ''
              }`"
            >
              <a-switch
                :checked="
                  projectStatusMap[record.nodeId] &&
                  projectStatusMap[record.nodeId][record.projectId] &&
                  projectStatusMap[record.nodeId][record.projectId].pid > 0
                "
                disabled
                checked-children="开"
                un-checked-children="关"
              />
            </a-tooltip>
            <span v-else>-</span>
          </template>
        </template>

        <template v-else-if="column.dataIndex === 'port'">
          <a-tooltip
            placement="topLeft"
            :title="`进程号：${(
              (projectStatusMap[record.nodeId] &&
                projectStatusMap[record.nodeId][record.projectId] &&
                projectStatusMap[record.nodeId][record.projectId].pids) || [
                (projectStatusMap[record.nodeId] &&
                  projectStatusMap[record.nodeId][record.projectId] &&
                  projectStatusMap[record.nodeId][record.projectId].pid) ||
                  '-'
              ]
            ).join(',')} / 端口号：${
              (projectStatusMap[record.nodeId] &&
                projectStatusMap[record.nodeId][record.projectId] &&
                projectStatusMap[record.nodeId][record.projectId].port) ||
              '-'
            }`"
          >
            <span
              >{{
                (projectStatusMap[record.nodeId] &&
                  projectStatusMap[record.nodeId][record.projectId] &&
                  projectStatusMap[record.nodeId][record.projectId].port) ||
                '-'
              }}/{{
                (
                  (projectStatusMap[record.nodeId] &&
                    projectStatusMap[record.nodeId][record.projectId] &&
                    projectStatusMap[record.nodeId][record.projectId].pids) || [
                    (projectStatusMap[record.nodeId] &&
                      projectStatusMap[record.nodeId][record.projectId] &&
                      projectStatusMap[record.nodeId][record.projectId].pid) ||
                      '-'
                  ]
                ).join(',')
              }}</span
            >
          </a-tooltip>
        </template>
        <template v-else-if="column.dataIndex === 'operation'">
          <a-space>
            <a-button size="small" type="primary" @click="handleFile(record)">文件</a-button>
            <template v-if="noFileModes.includes(record.runMode)">
              <a-button size="small" type="primary" @click="handleConsole(record)">控制台</a-button>
            </template>
            <template v-else>
              <a-tooltip title="文件类型没有控制台功能">
                <a-button size="small" type="primary" :disabled="true">控制台</a-button></a-tooltip
              >
            </template>

            <a-dropdown>
              <a @click="(e) => e.preventDefault()">
                更多
                <DownOutlined />
              </a>
              <template v-slot:overlay>
                <a-menu>
                  <a-menu-item>
                    <template v-if="noFileModes.includes(record.runMode)">
                      <a-button size="small" type="primary" @click="handleTrigger(record)">触发器</a-button>
                    </template>
                    <template v-else>
                      <a-tooltip title="文件类型没有触发器功能">
                        <a-button size="small" type="primary" :disabled="true">触发器</a-button></a-tooltip
                      >
                    </template>
                  </a-menu-item>
                  <a-menu-item v-if="noFileModes.includes(record.runMode)">
                    <a-button size="small" type="primary" @click="handleLogBack(record)">项目日志 </a-button>
                  </a-menu-item>
                  <a-menu-item>
                    <a-button size="small" type="primary" @click="copyItem(record)">复制</a-button>
                  </a-menu-item>
                  <a-menu-item>
                    <a-button size="small" type="primary" danger @click="handleDelete(record, '')">逻辑删除</a-button>
                  </a-menu-item>
                  <a-menu-item>
                    <a-button size="small" type="primary" danger @click="handleDelete(record, 'thorough')"
                      >彻底删除</a-button
                    >
                  </a-menu-item>
                  <a-menu-item>
                    <a-button size="small" type="primary" danger @click="migrateWorkspace(record)"
                      >迁移工作空间</a-button
                    >
                  </a-menu-item>
                  <a-menu-item>
                    <a-button
                      size="small"
                      type="primary"
                      :disabled="(listQuery.page - 1) * listQuery.limit + (index + 1) <= 1"
                      @click="sortItemHander(record, index, 'top')"
                      >置顶</a-button
                    >
                  </a-menu-item>
                  <a-menu-item>
                    <a-button
                      size="small"
                      type="primary"
                      :disabled="(listQuery.page - 1) * listQuery.limit + (index + 1) <= 1"
                      @click="sortItemHander(record, index, 'up')"
                      >上移</a-button
                    >
                  </a-menu-item>
                  <a-menu-item>
                    <a-button
                      size="small"
                      type="primary"
                      :disabled="(listQuery.page - 1) * listQuery.limit + (index + 1) === listQuery.total"
                      @click="sortItemHander(record, index, 'down')"
                    >
                      下移
                    </a-button>
                  </a-menu-item>
                </a-menu>
              </template>
            </a-dropdown>
          </a-space>
        </template>
      </template>
    </a-table>
    <!-- 项目文件组件 -->
    <a-drawer
      destroyOnClose
      :title="drawerTitle"
      placement="right"
      width="85vw"
      :open="drawerFileVisible"
      @close="onFileClose"
    >
      <file
        v-if="drawerFileVisible"
        :nodeId="temp.nodeId"
        :projectId="temp.projectId"
        :runMode="temp.runMode"
        @goConsole="goConsole"
        @goReadFile="goReadFile"
      />
    </a-drawer>
    <!-- 项目控制台组件 -->
    <a-drawer
      destroyOnClose
      :title="drawerTitle"
      placement="right"
      width="85vw"
      :open="drawerConsoleVisible"
      @close="onConsoleClose"
    >
      <console
        v-if="drawerConsoleVisible"
        :id="temp.id"
        :nodeId="temp.nodeId"
        :projectId="temp.projectId"
        @goFile="goFile"
      />
    </a-drawer>
    <!-- 项目跟踪文件组件 -->
    <a-drawer
      destroyOnClose
      :title="drawerTitle"
      placement="right"
      width="85vw"
      :open="drawerReadFileVisible"
      @close="onReadFileClose"
    >
      <file-read
        v-if="drawerReadFileVisible"
        :nodeId="temp.nodeId"
        :readFilePath="temp.readFilePath"
        :id="temp.id"
        :projectId="temp.projectId"
        @goFile="goFile"
      />
    </a-drawer>
    <!-- 批量操作状态 -->
    <a-modal destroyOnClose v-model:open="batchVisible" :title="temp.title" :footer="null" @cancel="batchClose">
      <a-list bordered :data-source="temp.data">
        <template v-slot:renderItem="{ item }">
          <a-list-item>
            <a-list-item-meta>
              <!-- <template #description> :="item.whitelistDirectory" </template> -->
              <template v-slot:title>
                <a> {{ item.name }}</a>
              </template>
            </a-list-item-meta>
            <div>
              <a-tooltip :title="`${item.cause || '未开始'}`">{{ item.cause || '未开始' }} </a-tooltip>
            </div>
          </a-list-item>
        </template>
      </a-list>
    </a-modal>
    <!-- 触发器 -->
    <a-modal
      destroyOnClose
      v-model:open="triggerVisible"
      title="触发器"
      width="50%"
      :footer="null"
      :maskClosable="false"
    >
      <a-form ref="editTriggerForm" :model="temp" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
        <a-tabs default-active-key="1">
          <template v-slot:rightExtra>
            <a-tooltip title="重置触发器 token 信息,重置后之前的触发器 token 将失效">
              <a-button type="primary" size="small" @click="resetTrigger">重置</a-button>
            </a-tooltip>
          </template>
          <a-tab-pane key="1" tab="执行">
            <a-space direction="vertical" style="width: 100%">
              <a-alert message="温馨提示" type="warning">
                <template v-slot:description>
                  <ul>
                    <li>单个触发器地址中：第一个随机字符串为项目ID(服务端)，第二个随机字符串为 token</li>
                    <li>
                      重置为重新生成触发地址,重置成功后之前的触发器地址将失效,触发器绑定到生成触发器到操作人上,如果将对应的账号删除触发器将失效
                    </li>
                    <li>批量触发参数 BODY json： [ { "id":"1", "token":"a","action":"status" } ]</li>
                  </ul>
                </template>
              </a-alert>

              <a-alert
                :key="item.value"
                v-for="item in triggerUses"
                type="info"
                :message="`${item.desc}触发器地址(点击可以复制)`"
              >
                <template v-slot:description>
                  <a-typography-paragraph
                    :copyable="{ tooltip: false, text: `${temp.triggerUrl}?action=${item.value}` }"
                  >
                    <a-tag>GET</a-tag>
                    <span>{{ `${temp.triggerUrl}?action=${item.value}` }} </span>
                  </a-typography-paragraph>
                </template>
              </a-alert>

              <a-alert type="info" :message="`批量触发器地址(点击可以复制)`">
                <template v-slot:description>
                  <a-typography-paragraph :copyable="{ tooltip: false, text: temp.batchTriggerUrl }">
                    <a-tag>POST</a-tag> <span>{{ temp.batchTriggerUrl }} </span>
                  </a-typography-paragraph>
                </template>
              </a-alert>
            </a-space>
          </a-tab-pane>
        </a-tabs>
      </a-form>
    </a-modal>
    <!-- 编辑区 -->
    <a-modal
      destroyOnClose
      v-model:open="editProjectVisible"
      width="60vw"
      title="编辑项目"
      :confirmLoading="confirmLoading"
      @ok="
        () => {
          this.confirmLoading = true
          this.$refs.edit.handleOk().finally(() => {
            this.confirmLoading = false
          })
        }
      "
      :maskClosable="false"
    >
      <a-form :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
        <a-form-item label="选择节点" help="编辑过程中可以切换节点但是要注意数据是否匹配">
          <a-select v-model:value="temp.nodeId" allowClear placeholder="请选择节点">
            <a-select-option v-for="(nodeName, key) in nodeMap" :key="key">{{ nodeName }}</a-select-option>
          </a-select>
        </a-form-item>
      </a-form>

      <project-edit
        v-if="temp.nodeId"
        ref="edit"
        @close="
          () => {
            editProjectVisible = false
            this.getNodeProjectData()
            this.loadGroupList()
          }
        "
        :data="temp"
        :nodeId="temp.nodeId"
        :projectId="temp.id"
      />
    </a-modal>
    <!-- 迁移到其他工作空间 -->
    <a-modal
      destroyOnClose
      :confirmLoading="confirmLoading"
      v-model:open="migrateWorkspaceVisible"
      width="50vw"
      title="迁移到其他工作空间"
      @ok="migrateWorkspaceOk"
      :maskClosable="false"
    >
      <a-space direction="vertical" style="width: 100%">
        <a-alert message="温馨提示" type="warning" show-icon>
          <template v-slot:description>
            项目可能支持关联如下数据：
            <ul>
              <li>
                在线构建（构建关联仓库、构建历史）

                <ol>
                  <li>如果关联的构建关联的仓库被多个构建绑定（使用）不能迁移</li>
                  <li>仓库自动迁移后可能会重复存在请手动解决</li>
                </ol>
              </li>
              <li>节点分发【暂不支持迁移】</li>
              <li>项目监控 【暂不支持迁移】</li>
              <li>日志阅读 【暂不支持迁移】</li>
            </ul>
          </template>
        </a-alert>
        <a-alert message="风险提醒" type="error" show-icon>
          <template v-slot:description>
            <ul>
              <li>如果垮机器（资产机器）迁移之前机器中的项目数据仅是逻辑删除（项目文件和日志均会保留）</li>
              <li>迁移操作不具有事务性质，如果流程被中断或者限制条件不满足可能产生冗余数据！！！！</li>
              <li>
                迁移前您检查迁出机器和迁入机器的连接状态和网络状态避免未知错误或者中断造成流程失败产生冗余数据！！！！
              </li>
            </ul>
          </template>
        </a-alert>
      </a-space>
      <a-form :model="temp" :label-col="{ span: 6 }" :wrapper-col="{ span: 14 }">
        <a-form-item> </a-form-item>
        <a-form-item label="选择工作空间" name="workspaceId">
          <a-select
            show-search
            :filter-option="
              (input, option) => {
                const children = option.children && option.children()
                return (
                  children &&
                  children[0].children &&
                  children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
                )
              }
            "
            v-model:value="temp.workspaceId"
            placeholder="请选择工作空间"
            @change="loadMigrateWorkspaceNodeList"
          >
            <a-select-option v-for="item in workspaceList" :key="item.id">{{ item.name }}</a-select-option>
          </a-select>
        </a-form-item>
        <a-form-item label="选择逻辑节点" name="nodeId">
          <a-select
            show-search
            :filter-option="
              (input, option) => {
                const children = option.children && option.children()
                return (
                  children &&
                  children[0].children &&
                  children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
                )
              }
            "
            v-model:value="temp.nodeId"
            placeholder="请选择逻辑节点"
          >
            <a-select-option v-for="item in migrateWorkspaceNodeList" :key="item.id">{{ item.name }}</a-select-option>
          </a-select>
        </a-form-item>
      </a-form>
    </a-modal>
    <!-- 日志备份 -->
    <a-modal
      destroyOnClose
      v-model:open="lobbackVisible"
      title="日志备份列表"
      width="850px"
      :footer="null"
      :maskClosable="false"
    >
      <ProjectLog v-if="lobbackVisible" :nodeId="temp.nodeId" :projectId="temp.projectId"></ProjectLog>
    </a-modal>
  </div>
</template>

<script>
import { getNodeListAll, getProjectList, sortItemProject, syncProject } from '@/api/node'
import {
  getRuningProjectInfo,
  noFileModes,
  operateProject,
  runModeList,
  getProjectTriggerUrl,
  getProjectGroupAll,
  deleteProject,
  migrateWorkspace,
  importTemplate,
  exportData,
  importData
} from '@/api/node-project'
import File from '@/pages/node/node-layout/project/project-file'
import Console from '../node/node-layout/project/project-console'
import {
  CHANGE_PAGE,
  COMPUTED_PAGINATION,
  PAGE_DEFAULT_LIST_QUERY,
  concurrentExecution,
  itemGroupBy,
  parseTime
} from '@/utils/const'
import FileRead from '@/pages/node/node-layout/project/project-file-read'
import ProjectEdit from '@/pages/node/node-layout/project/project-edit'

import { mapState } from 'pinia'
import { useUserStore } from '@/stores/user'
import { getWorkSpaceListAll } from '@/api/workspace'
import ProjectLog from '@/pages/node/node-layout/project/project-log.vue'
export default {
  components: {
    File,
    Console,
    FileRead,
    ProjectEdit,
    ProjectLog
  },
  props: {
    nodeId: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      projList: [],
      projectStatusMap: {},
      groupList: [],
      runModeList,
      selectedRowKeys: [],
      listQuery: Object.assign({}, PAGE_DEFAULT_LIST_QUERY),
      noFileModes,
      nodeMap: {},
      drawerTitle: '',
      loading: true,
      temp: {},
      drawerFileVisible: false,
      drawerConsoleVisible: false,
      drawerReadFileVisible: false,
      batchVisible: false,

      columns: [
        {
          title: '项目ID',
          dataIndex: 'projectId',
          width: 100,
          ellipsis: true
        },

        {
          title: '项目名称',
          dataIndex: 'name',
          // width: 200,
          ellipsis: true
        },
        {
          title: '项目分组',
          dataIndex: 'group',
          sorter: true,
          width: '100px',
          ellipsis: true,
          tooltip: true
        },
        {
          title: '节点名称',
          dataIndex: 'nodeId',
          width: 90,
          ellipsis: true
        },
        {
          title: '项目路径',
          dataIndex: 'path',
          ellipsis: true,
          width: 120
        },
        {
          title: '运行状态',
          dataIndex: 'status',
          align: 'center',
          width: 100,
          ellipsis: true
        },
        {
          title: '端口/PID',
          dataIndex: 'port',
          width: 100,
          ellipsis: true
        },

        {
          title: '运行方式',
          dataIndex: 'runMode',
          width: 90,
          ellipsis: true
        },
        {
          title: 'webhook',
          dataIndex: 'token',
          // width: 120,
          ellipsis: true,
          tooltip: true
        },
        {
          title: '创建时间',
          dataIndex: 'createTimeMillis',
          sorter: true,
          ellipsis: true,
          customRender: ({ text }) => parseTime(text),
          width: '170px'
        },
        {
          title: '修改时间',
          dataIndex: 'modifyTimeMillis',
          ellipsis: true,
          sorter: true,
          customRender: ({ text }) => parseTime(text),
          width: '170px'
        },
        {
          title: '排序值',
          dataIndex: 'sortValue',
          sorter: true,
          width: '80px'
        },
        {
          title: '操作',
          dataIndex: 'operation',
          align: 'center',
          fixed: 'right',

          width: '190px'
        }
      ],
      triggerVisible: false,
      triggerUses: [
        { desc: '查看状态', value: 'status' },
        { desc: '启动项目', value: 'start' },
        { desc: '停止项目', value: 'stop' },
        { desc: '重启项目', value: 'restart' }
      ],
      editProjectVisible: false,
      countdownTime: Date.now(),
      refreshInterval: 5,
      migrateWorkspaceVisible: false,
      workspaceList: [],
      migrateWorkspaceNodeList: [],
      lobbackVisible: false,
      confirmLoading: false
    }
  },
  computed: {
    ...mapState(useUserStore, ['getUserInfo']),
    filePath() {
      return (this.temp.whitelistDirectory || '') + (this.temp.lib || '')
    },
    pagination() {
      return COMPUTED_PAGINATION(this.listQuery)
    },
    rowSelection() {
      return {
        selectedRowKeys: this.selectedRowKeys,
        onChange: this.onSelectChange,
        columnWidth: '40px',
        getCheckboxProps: this.getCheckboxProps
      }
    },
    useSuggestions() {
      if (this.loading) {
        // 加载中不提示
        return false
      }
      if (!this.getUserInfo || !this.getUserInfo.systemUser) {
        // 没有登录或者不是超级管理员
        return false
      }
      if (Object.keys(this.nodeMap).length) {
        return false
      }
      return true
      // if (this.listQuery.page !== 1 || this.listQuery.total > 0) {
      //   // 不是第一页 或者总记录数大于 0
      //   return false;
      // }
      // // 判断是否存在搜索条件
      // const nowKeys = Object.keys(this.listQuery);
      // const defaultKeys = Object.keys(PAGE_DEFAULT_LIST_QUERY);
      // const dictOrigin = nowKeys.filter((item) => !defaultKeys.includes(item));
      // return dictOrigin.length === 0;
    }
  },
  mounted() {
    getNodeListAll().then((res) => {
      if (res.code === 200) {
        res.data.forEach((item) => {
          this.nodeMap = { ...this.nodeMap, [item.id]: item.name }
        })
        this.getNodeProjectData()
      }
    })
    this.countdownTime = Date.now() + this.refreshInterval * 1000
    //
    this.loadGroupList()
  },
  methods: {
    silenceLoadData() {
      if (this.$attrs.routerUrl !== this.$route.path) {
        // 重新计算倒计时
        this.countdownTime = Date.now() + this.refreshInterval * 1000
        return
      }
      this.getNodeProjectData(null, false)
    },
    getNodeProjectData(pointerEvent, loading) {
      this.loading = true
      this.listQuery.page = pointerEvent?.altKey || pointerEvent?.ctrlKey ? 1 : this.listQuery.page
      this.nodeId && (this.listQuery.nodeId = this.nodeId)

      getProjectList(this.listQuery, loading)
        .then((res) => {
          if (res.code === 200) {
            const resultList = res.data.result

            // const tempList = resultList.filter((item) => item.runMode !== 'File')
            // const fileList = resultList.filter((item) => item.runMode === 'File')
            this.projList = resultList // tempList.concat(fileList)

            this.listQuery.total = res.data.total

            const nodeProjects = itemGroupBy(this.projList, 'nodeId')
            this.getRuningProjectInfo(nodeProjects)

            // 重新计算倒计时
            this.countdownTime = Date.now() + this.refreshInterval * 1000
          }
        })
        .finally(() => {
          this.loading = false
        })
    },
    loadGroupList() {
      getProjectGroupAll().then((res) => {
        if (res.data) {
          this.groupList = res.data
        }
      })
    },
    getRuningProjectInfo(nodeProjects) {
      if (nodeProjects.length <= 0) {
        return
      }
      concurrentExecution(
        nodeProjects.map((item, index) => {
          return index
        }),
        3,
        (citem) => {
          // console.log(i);
          const data = nodeProjects[citem]
          return new Promise((resolve, reject) => {
            const ids = data.data.map((item) => {
              return item.projectId
            })
            if (ids.length <= 0) {
              return
            }
            const tempParams = {
              nodeId: data.type,
              ids: JSON.stringify(ids)
            }
            getRuningProjectInfo(tempParams, 'noTip')
              .then((res2) => {
                if (res2.code === 200) {
                  this.projectStatusMap = {
                    ...this.projectStatusMap,
                    [data.type]: res2.data
                  }
                  resolve()
                } else {
                  const data2 = {}
                  this.projList.forEach((item) => {
                    data2[item.projectId] = {
                      port: 0,
                      pid: 0,
                      error: res2.msg
                    }
                  })
                  this.projectStatusMap = {
                    ...this.projectStatusMap,
                    [data.type]: data2
                  }
                  reject()
                }
                // this.getRuningProjectInfo(nodeProjects, i + 1);
              })
              .catch(() => {
                const data2 = {}
                this.projList.forEach((item) => {
                  data2[item.projectId] = {
                    port: 0,
                    pid: 0,
                    error: '网络异常'
                  }
                })
                this.projectStatusMap = {
                  ...this.projectStatusMap,
                  [data.type]: data2
                }
                reject()
              })
          })
        }
      )
    },
    // 文件管理
    handleFile(record) {
      this.temp = Object.assign({}, record)
      this.drawerTitle = `文件管理(${this.temp.name})`
      this.drawerFileVisible = true
    },
    // 关闭文件管理对话框
    onFileClose() {
      this.drawerFileVisible = false
      this.getNodeProjectData()
    },
    // 控制台
    handleConsole(record) {
      this.temp = Object.assign({}, record)
      this.drawerTitle = `控制台(${this.temp.name})`
      this.drawerConsoleVisible = true
    },
    // 关闭控制台
    onConsoleClose() {
      this.drawerConsoleVisible = false
      this.getNodeProjectData()
    },
    //前往文件
    goFile() {
      // 关闭控制台
      this.onConsoleClose()
      this.onReadFileClose()
      this.handleFile(this.temp)
    },
    //前往控制台
    goConsole() {
      //关闭文件
      this.onFileClose()
      this.handleConsole(this.temp)
    },
    // 跟踪文件
    goReadFile(path, filename) {
      this.onFileClose()
      this.drawerReadFileVisible = true
      this.temp.readFilePath = (path + '/' + filename).replace(new RegExp('//', 'gm'), '/')
      this.drawerTitle = `跟踪文件(${filename})`
    },
    onReadFileClose() {
      this.drawerReadFileVisible = false
    },
    //选中项目
    onSelectChange(selectedRowKeys) {
      this.selectedRowKeys = selectedRowKeys
    },
    batchClose() {
      this.batchVisible = false
      this.getNodeProjectData()
      this.selectedRowKeys = []
    },
    /**
     * 将选中的 key 转为 data
     */
    selectedRowKeysToId() {
      return this.projList
        .filter((item) => {
          return this.selectedRowKeys.includes(item.id)
        })
        .map((item) => {
          return {
            projectId: item.projectId,
            nodeId: item.nodeId,
            runMode: item.runMode,
            name: item.name
          }
        })
      // return this.selectedRowKeys.map((item) => {})
    },
    // 更新数据
    updateBatchData(index, data2) {
      const data = this.temp.data
      data[index] = { ...data[index], ...data2 }

      this.temp = {
        ...this.temp,
        data: [...data]
      }
    },
    //批量开始
    batchStart() {
      if (this.selectedRowKeys.length <= 0) {
        $notification.warning({
          message: '请选中要启动的项目'
        })
        return
      }
      this.temp = {
        title: '批量启动',
        data: this.selectedRowKeysToId()
      }

      this.batchVisible = true
      this.batchOptInfo(0, '启动', 'start')
    },
    // 批量操作
    batchOptInfo(index, msg, opt) {
      if (index >= (this.temp?.data?.length || -1)) {
        return
      }
      const value = this.temp.data[index]
      value.cause = msg + '中'
      this.updateBatchData(index, value)
      if (value.runMode !== 'File') {
        const params = {
          nodeId: value.nodeId,
          id: value.projectId,
          opt: opt
        }

        operateProject(params)
          .then((data) => {
            value.cause = data.msg
            this.updateBatchData(index, value)
            this.batchOptInfo(index + 1, msg, opt)
          })
          .catch(() => {
            value.cause = msg + '失败'
            this.updateBatchData(index, value)
            this.batchOptInfo(index + 1, msg, opt)
          })
      } else {
        value.cause = '跳过'
        this.updateBatchData(index, value)
        this.batchOptInfo(index + 1, msg, opt)
      }
    },

    //批量重启
    batchRestart() {
      if (this.selectedRowKeys.length <= 0) {
        $notification.warning({
          message: '请选中要重启的项目'
        })
        return
      }
      this.temp = {
        title: '批量重新启动',
        data: this.selectedRowKeysToId()
      }
      this.batchVisible = true
      this.batchOptInfo(0, '重启', 'restart')
    },

    //批量关闭
    batchStop() {
      if (this.selectedRowKeys.length <= 0) {
        $notification.warning({
          message: '请选中要关闭的项目'
        })
      }
      this.temp = {
        title: '批量关闭启动',
        data: this.selectedRowKeysToId()
      }
      this.batchVisible = true
      this.batchOptInfo(0, '停止', 'stop')
    },

    // 获取复选框属性 判断是否可以勾选
    getCheckboxProps(record) {
      return {
        // props: {
        disabled: record.runMode === 'File',
        name: record.name
        // }
      }
    },
    // 分页、排序、筛选变化时触发
    changePage(pagination, filters, sorter) {
      this.listQuery = CHANGE_PAGE(this.listQuery, { pagination, sorter })
      this.getNodeProjectData()
    },
    reSyncProject(nodeId) {
      const that = this
      $confirm({
        title: '系统提示',
        zIndex: 1009,
        content: '确定要重新同步当前节点项目缓存信息吗？',
        okText: '确认',
        cancelText: '取消',
        async onOk() {
          return await new Promise((resolve, reject) => {
            // 删除
            syncProject(nodeId)
              .then((res) => {
                if (res.code == 200) {
                  $notification.success({
                    message: res.msg
                  })
                  that.getNodeProjectData()
                }
                resolve()
              })
              .catch(reject)
          })
        }
      })
    },
    // 排序
    sortItemHander(record, index, method) {
      const msgData = {
        top: '确定要将此数据置顶吗？',
        up: '确定要将此数上移吗？',
        down: '确定要将此数据下移吗？下移操作可能因为列表后续数据没有排序值操作无效！'
      }
      let msg = msgData[method] || '确定要操作吗？'
      if (!record.sortValue) {
        msg += ' 当前数据为默认状态,操后上移或者下移可能不会达到预期排序,还需要对相关数据都操作后才能达到预期排序'
      }
      // console.log(this.list, index, this.list[method === "top" ? index : method === "up" ? index - 1 : index + 1]);
      const compareId = this.projList[method === 'top' ? index : method === 'up' ? index - 1 : index + 1].id
      const that = this
      $confirm({
        title: '系统提示',
        zIndex: 1009,
        content: msg,
        okText: '确认',
        cancelText: '取消',
        async onOk() {
          return await new Promise((resolve, reject) => {
            //
            sortItemProject({
              id: record.id,
              method: method,
              compareId: compareId
            })
              .then((res) => {
                if (res.code == 200) {
                  $notification.success({
                    message: res.msg
                  })

                  that.getNodeProjectData()
                }
                resolve()
              })
              .catch(reject)
          })
        }
      })
      // console.log(record, index, method);
    },
    // 触发器
    handleTrigger(record) {
      this.temp = Object.assign({}, record)

      getProjectTriggerUrl({
        id: record.id
      }).then((res) => {
        if (res.code === 200) {
          this.fillTriggerResult(res)
          this.triggerVisible = true
        }
      })
    },
    // 重置触发器
    resetTrigger() {
      getProjectTriggerUrl({
        id: this.temp.id,
        rest: 'rest'
      }).then((res) => {
        if (res.code === 200) {
          $notification.success({
            message: res.msg
          })
          this.fillTriggerResult(res)
        }
      })
    },
    fillTriggerResult(res) {
      this.temp.triggerUrl = `${location.protocol}//${location.host}${res.data.triggerUrl}`
      this.temp.batchTriggerUrl = `${location.protocol}//${location.host}${res.data.batchTriggerUrl}`

      this.temp = { ...this.temp }
    },
    toNode(nodeId) {
      const newpage = this.$router.resolve({
        path: '/node/list',
        query: {
          ...this.$route.query,
          nodeId: nodeId,
          pId: 'manage',
          id: 'manageList'
        }
      })
      window.open(newpage.href, '_blank')
    },
    // 打开编辑
    openEdit(data) {
      // this.temp = {
      //   id: data.projectId,
      //   nodeId: data.nodeId,
      // };
      this.temp = { ...data, id: data.projectId }

      this.editProjectVisible = true
    },
    // 复制
    copyItem(record) {
      const temp = Object.assign({}, record)
      delete temp.id
      delete temp.createTimeMillis
      delete temp.outGivingProject
      this.temp = {
        ...temp,
        name: temp.name + '副本',
        id: temp.projectId + '_copy',
        lib: temp.lib + '_copy'
      }

      this.editProjectVisible = true
    },
    // 打开编辑
    openAdd() {
      this.temp = {
        nodeId: this.listQuery.nodeId
      }
      this.editProjectVisible = true
    },
    // 删除
    handleDelete(record, thorough) {
      const that = this
      $confirm({
        title: '系统提示',
        zIndex: 1009,
        content: thorough
          ? '真的要彻底删除项目么？彻底项目会自动删除项目相关文件奥(包含项目日志，日志备份，项目文件)'
          : '真的要删除项目么？删除项目不会删除项目相关文件奥,建议先清理项目相关文件再删除项目',
        okText: '确认',
        cancelText: '取消',
        async onOk() {
          return await new Promise((resolve, reject) => {
            // 删除
            const params = {
              nodeId: record.nodeId,
              id: record.projectId,
              thorough: thorough
            }
            deleteProject(params)
              .then((res) => {
                if (res.code === 200) {
                  $notification.success({
                    message: res.msg
                  })

                  that.getNodeProjectData()
                }
                resolve()
              })
              .catch(reject)
          })
        }
      })
    },
    // 加载工作空间数据
    loadWorkSpaceListAll() {
      getWorkSpaceListAll().then((res) => {
        if (res.code === 200) {
          this.workspaceList = res.data
        }
      })
    },
    // 迁移到其他工作空间
    migrateWorkspace(record) {
      this.temp = {
        id: record.id,
        originalWorkspaceId: record.workspaceId,
        originalNodeId: record.nodeId
      }
      // delete this.temp.workspaceId;

      this.migrateWorkspaceVisible = true
      this.loadWorkSpaceListAll()
    },
    // 获取节点
    loadMigrateWorkspaceNodeList() {
      if (!this.temp.workspaceId) {
        return
      }
      getNodeListAll({
        workspaceId: this.temp.workspaceId
      }).then((res) => {
        this.migrateWorkspaceNodeList = res.data || []
      })
    },
    // 迁移确认
    migrateWorkspaceOk() {
      if (!this.temp.workspaceId) {
        $notification.warn({
          message: '请选择工作空间'
        })
        return false
      }
      if (!this.temp.nodeId) {
        $notification.warn({
          message: '请选择逻辑节点'
        })
        return false
      }
      // 同步
      this.confirmLoading = true
      migrateWorkspace({
        id: this.temp.id,
        toWorkspaceId: this.temp.workspaceId,
        toNodeId: this.temp.nodeId
      })
        .then((res) => {
          if (res.code == 200) {
            $notification.success({
              message: res.msg
            })
            this.migrateWorkspaceVisible = false
            this.getNodeProjectData()
            return false
          }
        })
        .finally(() => {
          this.confirmLoading = false
        })
    },
    // 下载导入模板
    handlerImportTemplate() {
      window.open(
        importTemplate({
          nodeId: this.listQuery.nodeId
        }),
        '_blank'
      )
    },
    handlerExportData() {
      window.open(exportData({ ...this.listQuery }), '_blank')
    },
    // 导入
    importBeforeUpload(file) {
      const formData = new FormData()
      formData.append('file', file)
      formData.append('nodeId', this.listQuery.nodeId)
      importData(formData).then((res) => {
        if (res.code === 200) {
          $notification.success({
            message: res.msg
          })
          this.loadData()
        }
      })
    },
    // 日志备份列表
    handleLogBack(record) {
      this.temp = Object.assign({}, record)
      this.lobbackVisible = true
    }
  }
}
</script>

<style scoped>
:deep(.ant-statistic div) {
  display: inline-block;
}

:deep(.ant-statistic-content-value, .ant-statistic-content) {
  font-size: 16px;
}
</style>
